home *** CD-ROM | disk | FTP | other *** search
/ AI Game Programming Wisdom / AIGameProgrammingWisdom.iso / SourceCode / 11 Learning / 08 Manslow / TanksDoc.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2001-10-02  |  25.9 KB  |  761 lines

  1. //Tanks
  2. //Copyright John Manslow
  3. //29/09/2001
  4.  
  5. // TanksDoc.cpp : implementation of the CTanksDoc class
  6. //
  7.  
  8. #include "stdafx.h"
  9. #include "Tanks.h"
  10. #include "TanksDoc.h"
  11.  
  12. #ifdef _DEBUG
  13. #define new DEBUG_NEW
  14. #undef THIS_FILE
  15. static char THIS_FILE[] = __FILE__;
  16. #endif
  17.  
  18. const double pi=3.1415926535;
  19.  
  20. #include "CWorld.h"
  21. #include "CTank.h"
  22. #include "CProjectile.h"
  23. #include "CMLP.h"
  24. #include "CConditionalDistribution.h"
  25. #include "CUnconditionalDistribution.h"
  26. #include "math.h"
  27. #include "fstream.h"
  28.  
  29. //This information is worked out from the exemplar files so these values aren't too
  30. //important.
  31. unsigned long ulNumberOfPatterns=1000;
  32. unsigned long ulNumberOfErrorPatterns=1000;
  33.  
  34. //The number of inputs to the neural network that calculates the optimal barrel angle and to the conditional
  35. //aiming error distribution model
  36. unsigned long ulNumberOfInputs=3;
  37. unsigned long ulNumberOfErrorInputs=1;
  38.  
  39. //Ten hidden neurons are used in the barrel angle MLP, and six in the MLP component of the conditional error
  40. //distribution model. You should generally use as few as possible, since networks with smaller numbers 
  41. //train more quickly, operate more quickly once trained and tend to learn the exemplars more robustly.
  42. unsigned long ulNumberOfHiddenNodes=10;
  43. unsigned long ulNumberOfHiddenNodesInConditionalErrorModel=6;
  44.  
  45. //This many bins gives good resolution but produces overfitting in the conditional error distribution model when 
  46. //the preceding shot was poor (since such shots are relatively rare in the exemplar data). This isn't a huge problem
  47. //in game, since such shots are rare there too!
  48. unsigned long ulNumberOfBinsInDistributionModels=50;
  49.  
  50. //For the barrel angle MLP, we have just one output - the angle of the AI tank's barrel taht is necessary to hit 
  51. //the player.
  52. unsigned long ulNumberOfOutputs=1;
  53.  
  54. //This level of error on the training samples was found to produce a barrel angle neural network that hit the
  55. //player's tank around 98% of the time. The value of termination error will have to be changed
  56. //for different types of error measure (see CMLP::dGetPerformance).
  57. double dTerminationError=0.000025;
  58.  
  59. //The error measure used by the conditional probability model has different units to that used by the neural network
  60. //that calculates the AI tank's barrel angle. In fact, for the distribution model, the units are log-probabilities. Terminating
  61. //training at this error seems to give a good distribution of aiming errors for the AI tank
  62. double dErrorModelTerminationError=2.455;
  63.  
  64. //Pointers to the distribution models, the barrel angle MLP, and the game world object
  65. CConditionalDistribution *pErrorDistribution;
  66. CUnconditionalDistribution *pUnconditionalErrorDistribution;
  67. CMLP *pMLP;
  68. CWorld *pWorld;
  69.  
  70. //Should always be true. See the book Game Programming Gems 2 for the original purpose of this flag. 
  71. BOOL boGeneratingTrainingData=FALSE;
  72.  
  73. //A flag to indicate whether we're just generating training data (i.e. writing examples of
  74. //aiming errors to disk or actually playing a proper game. In the former case, the AI doesn't get
  75. //a turn and the player controls the AI tank. The aiming errors made as the player does this
  76. //are logged to disk and can be used later to train the unconditional and conditional aiming error 
  77. //distribution models.
  78. BOOL boGeneratingErrorTrainingData=FALSE;
  79.  
  80. //Should always be true. See the book Game Programming Gems 2 for the original purpose of this flag. 
  81. BOOL boLoadTrainedNetwork=TRUE;
  82.  
  83. //When true, tells the game to load an pre-trained conditional distribution model. When 
  84. //false causes the game to create a new model and train it using examples loaded from disk
  85. //(which were generated by playing the game with boGeneratingErrorTrainingData=TRUE).
  86. //Note that unconditional distribution models are so quick to create we don't bother saving them 
  87. //and re-train them every time the game runs
  88. BOOL boLoadTrainedErrorNetwork=TRUE;
  89.  
  90. //Information used to scale the inputs to the various models (see below)
  91. double *pdMin;
  92. double *pdMax;
  93. double *pdErrorInputMin;
  94. double *pdErrorInputMax;
  95. double dErrorMin,dErrorMax;
  96.  
  97. //The file containing the exemplar data
  98. #define ExemplarData "BarrelAngleExemplarData.txt"
  99.  
  100. //#define ErrorExemplarData "NewErrorExemplarData.txt"
  101. #define ErrorExemplarData "AimingErrorExemplarData.txt"
  102.  
  103. //The file containing the trained neural network that is used to calculate the optimal barrel angle for the AI tank
  104. #define TrainedMLP "TrainedBarrelAngleMLP.mlp"
  105.  
  106. //The file containing the trained aiming error distribution model that is used to add random
  107. //variation to the aiming of the AI tank.
  108. #define TrainedConditionalDistributionModel "TrainedAimingErrorModel.cdm"
  109.  
  110. IMPLEMENT_DYNCREATE(CTanksDoc, CDocument)
  111.  
  112. BEGIN_MESSAGE_MAP(CTanksDoc, CDocument)
  113.     //{{AFX_MSG_MAP(CTanksDoc)
  114.         // NOTE - the ClassWizard will add and remove mapping macros here.
  115.         //    DO NOT EDIT what you see in these blocks of generated code!
  116.     //}}AFX_MSG_MAP
  117. END_MESSAGE_MAP()
  118.  
  119. CTanksDoc::CTanksDoc()
  120. {
  121.     //Seed the random number generator
  122.     srand(unsigned(time(NULL)));
  123.  
  124.     TRACE("---------------------------------------------------------------------------------\n");
  125.     TRACE("Initialising.\n");
  126.     TRACE("---------------------------------------------------------------------------------\n");
  127.  
  128.     //Create the game world. The terrain will be 760 units long.
  129.     TRACE("Creating world...\n");
  130.     pWorld=new CWorld(760);
  131.  
  132.     //Check to make sure it was a success.
  133.     if(pWorld)
  134.     {
  135.         TRACE("successful.\n");
  136.     }
  137.     else
  138.     {
  139.         //If not, inform the user and assert.
  140.         TRACE("failed.\n");
  141.         ASSERT(FALSE);
  142.     }
  143.  
  144.     //Initialise these arrays with NULL pointers so we don't try to delete them later
  145.     //even if they're unused.
  146.     pdMin=NULL;
  147.     pdMax=NULL;
  148.  
  149.     /******************************************************************************************************************/
  150.     //This section of code loads training data for and trains the MLP neural network that computes the "optimal"
  151.     //angle for the AI tank's barrel. The way this is done was described in detail in the book 
  152.     //"Game Programming Gems 2".
  153.     if(!boGeneratingTrainingData)
  154.     {
  155.         unsigned long i,j;
  156.         TRACE("Opening training data file...");
  157.  
  158.         //Open the file containing the training data.
  159.         ifstream *pTrainingData;
  160.         pTrainingData=new ifstream(ExemplarData,ios::nocreate);
  161.         if(pTrainingData)
  162.         {
  163.             TRACE("successful.\n");
  164.         }
  165.         else
  166.         {
  167.             TRACE("failed.\n");
  168.             ASSERT(FALSE);
  169.         }
  170.  
  171.         //Read in the number of examples (patterns) the file contains and how many inputs. In this
  172.         //case, there should be three inputs, corresponging to x and y displacement between the
  173.         //tanks and wind speed. We don't need to load the number of outputs because in this 
  174.         //application, we'll always have only one - the angle of the tank's barrel
  175.         *pTrainingData>>ulNumberOfPatterns;
  176.         *pTrainingData>>ulNumberOfInputs;
  177.         
  178.         TRACE("Loading training data...");
  179.  
  180.         //Allocate some memory for the example data
  181.         double **ppdTrainingInputs;
  182.         double **ppdTrainingTargets;
  183.  
  184.         ppdTrainingInputs=new double*[ulNumberOfPatterns];
  185.         ppdTrainingTargets=new double*[ulNumberOfPatterns];
  186.  
  187.         //Allocate memory to record the maximum and minimum values of each input
  188.         pdMin=new double[ulNumberOfInputs];
  189.         pdMax=new double[ulNumberOfInputs];
  190.  
  191.         //If any of the memory allocation failed, alert the user.
  192.         if(!(    ppdTrainingInputs &&
  193.                 ppdTrainingTargets &&
  194.                 pdMin &&
  195.                 pdMax))
  196.         {
  197.             TRACE("failed.\n");
  198.             ASSERT(FALSE);
  199.         }
  200.  
  201.         //Initialise the min/max statistics to large values to ensure that they'll be overwritten
  202.         //when the data are analysed.
  203.         for(i=0;i<ulNumberOfInputs;i++)
  204.         {
  205.             pdMin[i]=1000.0;
  206.             pdMax[i]=-1000.0;
  207.         }
  208.  
  209.         //This code loads the example data and records the minimum and maximum values attained by
  210.         //each input
  211.         for(i=0;i<ulNumberOfPatterns;i++)
  212.         {
  213.             //Allocate memory to store the ith input example and check to make sure it succeded
  214.             ppdTrainingInputs[i]=new double[ulNumberOfInputs];
  215.             if(!ppdTrainingInputs[i])
  216.             {
  217.                 TRACE("failed.\n");
  218.                 ASSERT(FALSE);
  219.             }
  220.  
  221.             //Load the ith example
  222.             for(j=0;j<ulNumberOfInputs;j++)
  223.             {
  224.                 *pTrainingData>>ppdTrainingInputs[i][j];
  225.             }
  226.  
  227.             //Allocate memory to store the corresponding output (barrel angle) of the ith pattern
  228.             ppdTrainingTargets[i]=new double[1];
  229.             if(!ppdTrainingTargets[i])
  230.             {
  231.                 TRACE("failed.\n");
  232.                 ASSERT(FALSE);
  233.             }
  234.  
  235.             //Load it
  236.             *pTrainingData>>ppdTrainingTargets[i][0];
  237.  
  238.             //Maintain the record of the maximum and minimum values of each input
  239.             for(j=0;j<ulNumberOfInputs;j++)
  240.             {
  241.                 if(ppdTrainingInputs[i][j]<pdMin[j])
  242.                 {
  243.                     pdMin[j]=ppdTrainingInputs[i][j];
  244.                 }
  245.                 if(ppdTrainingInputs[i][j]>pdMax[j])
  246.                 {
  247.                     pdMax[j]=ppdTrainingInputs[i][j];
  248.                 }
  249.             }
  250.         }
  251.  
  252.         pTrainingData->close();
  253.         delete pTrainingData;
  254.  
  255.         //Once all data has been loaded, this code scales the inputs so that they all lie in the range
  256.         //-1 to +1. This is not strictly necessary but can often speed up neural network learning
  257.         //quite significantly. Note that all values put into the network in future must be scaled 
  258.         //in the same way, so the array of min/max values for each input have to be stored for future 
  259.         //use. For example, look in the OnTimer function in TanksView.cpp where the inputs to the
  260.         //network are scaled using the same min/max values used here.
  261.         for(i=0;i<ulNumberOfPatterns;i++)
  262.         {
  263.             for(j=0;j<ulNumberOfInputs;j++)
  264.             {
  265.                 //Inputs range between min and max
  266.                 ppdTrainingInputs[i][j]-=pdMin[j];
  267.                 //Inputs range between 0 and max-min
  268.                 ppdTrainingInputs[i][j]/=(pdMax[j]-pdMin[j]);
  269.                 //Inputs range between 0 and 1
  270.                 ppdTrainingInputs[i][j]-=0.5;
  271.                 //Inputs range between -0.5 and +0.5
  272.                 ppdTrainingInputs[i][j]*=2.0;
  273.                 //Inputs range between -1.0 and +1.0
  274.             }
  275.         }
  276.         TRACE("successful.\n");
  277.  
  278.         //Now we have the example data with which to teach a neural network, we need a network
  279.         //to teach.
  280.  
  281.         //Create the MLP neural network, telling it how many inputs we need (3 in this case,
  282.         //x-displacement, y-displacement, and wind speed), how many hidden neurons (or nodes)
  283.         //and how many outputs (only one - for the inclination of the AI tank's barrel). Ten hidden
  284.         //neurons are used here, but you should generally use as few a possible. This helps to
  285.         //speed training and maximise performance in-game. The MLP created has a random set of
  286.         //weights and hence will not do anything useful unless it is trained or a trained set of 
  287.         //weights is loaded into it (as with the pMLP->Load call below).
  288.         pMLP=new CMLP(
  289.                         ulNumberOfInputs,
  290.                         ulNumberOfHiddenNodes,
  291.                         ulNumberOfOutputs
  292.                         );
  293.  
  294.         //Create a variable to store return values
  295.         int nReturnValue;
  296.  
  297.         //Do we want to load a pre-trained network?
  298.         if(boLoadTrainedNetwork)
  299.         {
  300.             //If yes, load it.
  301.             TRACE("Loading MLP...");
  302.             nReturnValue=pMLP->Load(&TrainedMLP);
  303.             if(nReturnValue)
  304.             {
  305.                 TRACE("successful.\n");
  306.             }
  307.             else
  308.             {
  309.                 TRACE("failed.\n");
  310.                 ASSERT(FALSE);
  311.             }
  312.         }
  313.  
  314.         TRACE("Training MLP...\n");
  315.  
  316.         //Create a variable to record the number of training iterations
  317.         unsigned long ulIteration=0;
  318.  
  319.         //This do-while loop actually does the training. It continually calls the neural network's
  320.         //training function (each call doing only a single training step) until the network's
  321.         //ability to reproduce the targets (barrel angles) contained in the example data (as
  322.         //measured by the network's dBestError variable) is adequate. This training process will
  323.         //require many tens or hundred of thousands of steps and can last several hours. Of course,
  324.         //this shouldn't really be done here in the constructor...
  325.         do
  326.         {
  327.             //To perform a training step, tell the network how many patterns (examples) there are
  328.             //in the example data and pass it pointers to it.
  329.             pMLP->dTrainingStep(
  330.                                     ulNumberOfPatterns,
  331.                                     ppdTrainingInputs,
  332.                                     ppdTrainingTargets
  333.                                     );
  334.  
  335.  
  336.             //Every hundred training steps provide some feedback on the progress of the network's
  337.             //learning
  338.             if(ulIteration%100==0)
  339.             {
  340.                 TRACE("\n\tIteration: %9u  Training Error: %+3.12e",
  341.                                 ulIteration,
  342.                                 pMLP->dGetPerformance());
  343.             }
  344.  
  345.             //Keep a count of the number of steps so far
  346.             ulIteration++;
  347.         }
  348.         //Keep going until the network's ability to reproduce the barrel angles in the example
  349.         //data is good enough. The error produced by the network will never be zero, so 
  350.         //dTerminationError will need to be some positive value. Some experimentation will be
  351.         //required to see what value of dTerminationError is required to give adequate performance
  352.         //in game. Start off with quite large values of dTerminationError like 0.1 and work down.
  353.         //Bear in mind that if the output variable varies wildly, larger errors will tend to be 
  354.         //produced. I.e. if the output varies between +1000 and -1000, then a termination error of, 
  355.         //say, 50 may be more suitable.
  356.         while(
  357.                 pMLP->dGetPerformance()>dTerminationError &&
  358.                 !boGeneratingTrainingData
  359.                 );
  360.  
  361.         TRACE("\nsuccessful.\n");
  362.  
  363.         //Once we've finished training, we don't need the exemplar data any more, so we can delete it.
  364.         for(i=0;i<ulNumberOfPatterns;i++)
  365.         {
  366.             delete []ppdTrainingInputs[i];
  367.             delete []ppdTrainingTargets[i];
  368.         }
  369.         delete []ppdTrainingInputs;
  370.         delete []ppdTrainingTargets;
  371.         
  372.         //Save the trained network
  373.         TRACE("Saving trained MLP...");
  374.  
  375.         //We'll save this new network under a different name so we don't overwrite the old version
  376.         nReturnValue=pMLP->Save(&"NewTrainedMLP.mlp");
  377.         if(nReturnValue)
  378.         {
  379.             TRACE("successful.\n");
  380.         }
  381.         else
  382.         {
  383.             TRACE("failed.\n");
  384.             ASSERT(FALSE);
  385.         }
  386.     }
  387.     /******************************************************************************************************************/
  388.     //This code loads the examples of aiming errors, scales them as required by the unconditional and
  389.     //conditional distribution models, and trains those models.
  390.     if(!boGeneratingErrorTrainingData)
  391.     {
  392.         unsigned long i,j;
  393.         TRACE("Opening error training data file...");
  394.  
  395.         //Open the file containing the error training data.
  396.         ifstream *pErrorTrainingData;
  397.         pErrorTrainingData=new ifstream(ErrorExemplarData,ios::nocreate);
  398.         if(pErrorTrainingData)
  399.         {
  400.             TRACE("successful.\n");
  401.         }
  402.         else
  403.         {
  404.             TRACE("failed.\n");
  405.             ASSERT(FALSE);
  406.         }
  407.  
  408.         //Read in the number of examples the file contains.
  409.         *pErrorTrainingData>>ulNumberOfErrorPatterns;
  410.         *pErrorTrainingData>>ulNumberOfErrorInputs;
  411.         
  412.         //Create a new conditional distribution model that will be used to capture the relationship between the
  413.         //aiming error made on one shot and the error on the next. 
  414.         pErrorDistribution=new CConditionalDistribution(
  415.                                                                                             ulNumberOfErrorInputs,
  416.                                                                                             ulNumberOfHiddenNodesInConditionalErrorModel,
  417.                                                                                             ulNumberOfBinsInDistributionModels);
  418.         if(boLoadTrainedErrorNetwork)
  419.         {
  420.             //If we've already trained one, load it
  421.             pErrorDistribution->Load(TrainedConditionalDistributionModel);
  422.         }
  423.  
  424.         //Create a new unconditional distribution model that will be used to represent the distribution of aiming
  425.         //errors made on the first shot of each game
  426.         pUnconditionalErrorDistribution=new CUnconditionalDistribution(ulNumberOfBinsInDistributionModels);
  427.  
  428.         TRACE("Loading error training data...");
  429.  
  430.         //Allocate some memory for the example data
  431.         double **ppdErrorTrainingInputs;
  432.         double *pdErrorTrainingTargets;
  433.  
  434.         ppdErrorTrainingInputs=new double*[ulNumberOfErrorPatterns];
  435.         pdErrorTrainingTargets=new double[ulNumberOfErrorPatterns];
  436.  
  437.         //Allocate memory to record the maximum and minimum values of each input. All inputs to the conditional
  438.         //distribution model need to be scaled into the range -1 to +1, and the example outputs for both models
  439.         //in 0 to +1.
  440.         pdErrorInputMin=new double[ulNumberOfErrorInputs];
  441.         pdErrorInputMax=new double[ulNumberOfErrorInputs];
  442.  
  443.         //If any of the memory allocation failed, alert the user.
  444.         if(!(    ppdErrorTrainingInputs &&
  445.                 pdErrorTrainingTargets &&
  446.                 pdErrorInputMin &&
  447.                 pdErrorInputMax))
  448.         {
  449.             TRACE("failed.\n");
  450.             ASSERT(FALSE);
  451.         }
  452.  
  453.         //Initialise the min/max statistics to large values to ensure that they'll be overwritten
  454.         //when the data are analysed.
  455.         for(i=0;i<ulNumberOfErrorInputs;i++)
  456.         {
  457.             pdErrorInputMin[i]=1000.0;
  458.             pdErrorInputMax[i]=-1000.0;
  459.         }
  460.         dErrorMin=1000.0;
  461.         dErrorMax=-1000.0;
  462.  
  463.         //This code loads the example data and records the minimum and maximum values attained by
  464.         //each input
  465.  
  466.          //Each line of the data file consists of a number indicating when the shot occurred in the game 
  467.         //(i.e. 1 means the first shot of a new game) and the angular error that the player made when 
  468.         //aiming on that shot
  469.         for(i=0;i<ulNumberOfErrorPatterns;i++)
  470.         {
  471.             //Allocate memory to store the ith input example and check to make sure it succeded
  472.             ppdErrorTrainingInputs[i]=new double[ulNumberOfErrorInputs];
  473.             if(!ppdErrorTrainingInputs[i])
  474.             {
  475.                 TRACE("failed.\n");
  476.                 ASSERT(FALSE);
  477.             }
  478.  
  479.             //Load the ith example
  480.             for(j=0;j<ulNumberOfErrorInputs;j++)
  481.             {
  482.                 *pErrorTrainingData>>ppdErrorTrainingInputs[i][j];
  483.             }
  484.  
  485.             //Allocate memory to store the corresponding output (angular aiming error in rads) of the ith pattern
  486.             if(!pdErrorTrainingTargets[i])
  487.             {
  488.                 TRACE("failed.\n");
  489.                 ASSERT(FALSE);
  490.             }
  491.  
  492.             //Load it
  493.             *pErrorTrainingData>>pdErrorTrainingTargets[i];
  494.  
  495.             if(pdErrorTrainingTargets[i]<dErrorMin)
  496.             {
  497.                 dErrorMin=pdErrorTrainingTargets[i];
  498.             }
  499.             if(pdErrorTrainingTargets[i]>dErrorMax)
  500.             {
  501.                 dErrorMax=pdErrorTrainingTargets[i];
  502.             }
  503.  
  504.             //Maintain a record of the maximum and minimum values of each input
  505.             for(j=0;j<ulNumberOfErrorInputs;j++)
  506.             {
  507.                 if(ppdErrorTrainingInputs[i][j]<pdErrorInputMin[j])
  508.                 {
  509.                     pdErrorInputMin[j]=ppdErrorTrainingInputs[i][j];
  510.                 }
  511.                 if(ppdErrorTrainingInputs[i][j]>pdErrorInputMax[j])
  512.                 {
  513.                     pdErrorInputMax[j]=ppdErrorTrainingInputs[i][j];
  514.                 }
  515.             }
  516.         }
  517.  
  518.         //Close and delete the exemplar data file
  519.         pErrorTrainingData->close();
  520.         delete pErrorTrainingData;
  521.  
  522.         //Now scale all inputs to lie between -1.0 and +1.0
  523.         for(i=0;i<ulNumberOfErrorPatterns;i++)
  524.         {
  525.             for(j=0;j<ulNumberOfErrorInputs;j++)
  526.             {
  527.                 //Inputs range between min and max
  528.                 ppdErrorTrainingInputs[i][j]-=pdErrorInputMin[j];
  529.                 //Inputs range between 0 and max-min
  530.                 ppdErrorTrainingInputs[i][j]/=(pdErrorInputMax[j]-pdErrorInputMin[j]);
  531.                 //Inputs range between 0 and 1
  532.                 ppdErrorTrainingInputs[i][j]-=0.5;
  533.                 //Inputs range between -0.5 and +0.5
  534.                 ppdErrorTrainingInputs[i][j]*=2.0;
  535.                 //Inputs range between -1.0 and +1.0
  536.             }
  537.         }
  538.  
  539.         //Scale the distribution model targets to lie between 0 to +1. This needs to be done
  540.         //because the positions of the bins in the models are fixed and distributed evenly in this range.
  541.         for(i=0;i<ulNumberOfErrorPatterns;i++)
  542.         {
  543.             pdErrorTrainingTargets[i]-=dErrorMin;
  544.             pdErrorTrainingTargets[i]/=(dErrorMax-dErrorMin);
  545.         }
  546.  
  547.         TRACE("successful.\n");
  548.  
  549.         //Work out how many examples we're going to have to train the unconditional and conditional models.
  550.         //(See below for more details of how this works.)
  551.         unsigned long ulNumberOfUnconditionalPatterns=0;
  552.         unsigned long ulNumberOfConditionalPatterns=0;
  553.         for(i=0;i<ulNumberOfErrorPatterns;i++)
  554.         {
  555.             if(ppdErrorTrainingInputs[i][0]==-1)
  556.             {
  557.                 ulNumberOfUnconditionalPatterns++;
  558.             }
  559.             else
  560.             {
  561.                 ulNumberOfConditionalPatterns++;
  562.             }
  563.         }
  564.  
  565.         //Allocate memory to store seperate data sets that will be used to train the unconditional and conditional
  566.         //distribution models. Note that the number of inputs to the conditional distribution is fixed at one in this 
  567.         //application because we're are assuming that the distribution of aiming errors on each shot is primarily
  568.         //affected by the aiming error on the preceding shot.
  569.         double *pdUnconditionalTrainingTargets=new double[ulNumberOfUnconditionalPatterns];
  570.         double *pdConditionalTrainingTargets=new double[ulNumberOfConditionalPatterns];
  571.         double **ppdConditionalTrainingInputs=new double*[ulNumberOfConditionalPatterns];
  572.         for(i=0;i<ulNumberOfConditionalPatterns;i++)
  573.         {
  574.             ppdConditionalTrainingInputs[i]=new double[1];
  575.         }
  576.     
  577.         //This section of code partitions the exemplar data into unconditional and conditional data sets. The 
  578.         //unconditional data set contains the aiming errors made on the first shot of each game. The conditional
  579.         //data set consists of input-output pairs, where, for each pair, the input consists of the aiming error
  580.         //made on the previous shot, and the output the aiming error made on the current shot. The conditional 
  581.         //model of aiming errors thus represents the effect of the accuracy of each shot on the accuracy of the next.
  582.         double dLastError=0.0;
  583.         ulNumberOfUnconditionalPatterns=0;
  584.         ulNumberOfConditionalPatterns=0;
  585.         for(i=0;i<ulNumberOfErrorPatterns;i++)
  586.         {
  587.             //This condition is true if the current pattern (example) was the first shot of a new game
  588.             if(ppdErrorTrainingInputs[i][0]==-1)
  589.             {
  590.                 //If it was, add it to the data that will be used to train the unconditional distribution
  591.                 pdUnconditionalTrainingTargets[ulNumberOfUnconditionalPatterns]=pdErrorTrainingTargets[i];
  592.                 ulNumberOfUnconditionalPatterns++;
  593.             }
  594.             else
  595.             {
  596.                 //If it wasn't, add it as a target output for the conditional distribution model...
  597.                 pdConditionalTrainingTargets[ulNumberOfConditionalPatterns]=pdErrorTrainingTargets[i];
  598.  
  599.                 //...and set the corresponding input to be equal to the error made on the preceding shot. Note that
  600.                 //this has to be re-scaled to be between -1 and +1.
  601.                 ppdConditionalTrainingInputs[ulNumberOfConditionalPatterns][0]=2.0*(dLastError-0.5);
  602.                 ulNumberOfConditionalPatterns++;
  603.             }
  604.  
  605.             //Keep a record of the aiming error that was made on the current shot
  606.             dLastError=pdErrorTrainingTargets[i];
  607.         }
  608.         
  609.         //Now we've copied this data into two new data sets, we can delete the original
  610.         for(i=0;i<ulNumberOfErrorPatterns;i++)
  611.         {
  612.             delete []ppdErrorTrainingInputs[i];
  613.         }
  614.         delete []ppdErrorTrainingInputs;
  615.         delete []pdErrorTrainingTargets;
  616.         
  617.         TRACE("Training error distribution model...\n");
  618.         unsigned long ulIteration=0;
  619.  
  620.         //This do-while loop trains the conditional distribution model. It continually calls the distribution's
  621.         //training function until the measured performance is adequate. The process typically requires
  622.         //many tens or hundred of thousands of steps and can last several hours. In fact, the trained model provided
  623.         //on the CD was produced by training over night using an Intel Celeron 500MHz processor.
  624.         do
  625.         {
  626.             //To perform a training step, tell the model how many patterns (examples) there are
  627.             //in the example data and pass it pointers to it.
  628.             pErrorDistribution->dTrainingStep(
  629.                                     ulNumberOfConditionalPatterns,
  630.                                     ppdConditionalTrainingInputs,
  631.                                     pdConditionalTrainingTargets
  632.                                     );
  633.  
  634.  
  635.  
  636.             //Every hundred training steps provide some feedback on the progress of the model's
  637.             //learning (if in debug mode)
  638.             if(ulIteration%100==0)
  639.             {
  640.                 TRACE("\n\tIteration: %9u\tTraining Error: %+12.6e\tStep Size: %12.6e",
  641.                                 ulIteration,
  642.                                 pErrorDistribution->dGetPerformance(),
  643.                                 pErrorDistribution->dStepSize);
  644.             }
  645.  
  646.             //Keep a count of the number of steps so far
  647.             ulIteration++;
  648.         }
  649.         while(
  650.                     pErrorDistribution->dGetPerformance()>dErrorModelTerminationError
  651.                 );
  652.  
  653.         TRACE("\nsuccessful.\n");
  654.  
  655.         //Once we've finished training, we don't need the processed versions of the exemplar data
  656.         //so we can delete them
  657.         for(i=0;i<ulNumberOfConditionalPatterns;i++)
  658.         {
  659.             delete []ppdConditionalTrainingInputs[i];
  660.         }
  661.         delete []ppdConditionalTrainingInputs;
  662.         delete []pdConditionalTrainingTargets;
  663.  
  664.         //Train the unconditional distribution
  665.         pUnconditionalErrorDistribution->dTrainingStep(ulNumberOfUnconditionalPatterns,pdUnconditionalTrainingTargets);
  666.  
  667.         //Delete the unconditional exemplar data
  668.         delete []pdUnconditionalTrainingTargets;
  669.     
  670.     }
  671.  
  672.     TRACE("---------------------------------------------------------------------------------\n");
  673.     TRACE("Game starting.\n");
  674.     TRACE("---------------------------------------------------------------------------------\n");
  675. }
  676.  
  677. CTanksDoc::~CTanksDoc()
  678. {
  679.     //Deallocate memory:
  680.     TRACE("---------------------------------------------------------------------------------\n");
  681.     TRACE("Game finishing.\n");
  682.     TRACE("---------------------------------------------------------------------------------\n");
  683.  
  684.     //If the scaling information exists, delete it
  685.     if(pdMin)
  686.     {
  687.         delete []pdMin;
  688.     }
  689.     if(pdMax)
  690.     {
  691.         delete []pdMax;
  692.     }
  693.     if(pdErrorInputMin)
  694.     {
  695.         delete []pdErrorInputMin;
  696.     }
  697.     if(pdErrorInputMax)
  698.     {
  699.         delete []pdErrorInputMax;
  700.     }
  701.  
  702.     //The neural networks
  703.     delete pMLP;
  704.     delete pErrorDistribution;
  705.     delete pUnconditionalErrorDistribution;
  706.  
  707.     //And the game world
  708.     TRACE("Deleting world...\n");
  709.     delete pWorld;
  710.     TRACE("successful.\n");
  711.  
  712.     //That's it, we've finished!
  713.     TRACE("---------------------------------------------------------------------------------\n");
  714.     TRACE("Finished.\n");
  715.     TRACE("---------------------------------------------------------------------------------\n");
  716. }
  717.  
  718. BOOL CTanksDoc::OnNewDocument()
  719. {
  720.     if (!CDocument::OnNewDocument())
  721.         return FALSE;
  722.  
  723.     // TODO: add reinitialization code here
  724.     // (SDI documents will reuse this document)
  725.  
  726.     return TRUE;
  727. }
  728.  
  729. /////////////////////////////////////////////////////////////////////////////
  730. // CTanksDoc serialization
  731.  
  732. void CTanksDoc::Serialize(CArchive& ar)
  733. {
  734.     if (ar.IsStoring())
  735.     {
  736.         // TODO: add storing code here
  737.     }
  738.     else
  739.     {
  740.         // TODO: add loading code here
  741.     }
  742. }
  743.  
  744. /////////////////////////////////////////////////////////////////////////////
  745. // CTanksDoc diagnostics
  746.  
  747. #ifdef _DEBUG
  748. void CTanksDoc::AssertValid() const
  749. {
  750.     CDocument::AssertValid();
  751. }
  752.  
  753. void CTanksDoc::Dump(CDumpContext& dc) const
  754. {
  755.     CDocument::Dump(dc);
  756. }
  757. #endif //_DEBUG
  758.  
  759. /////////////////////////////////////////////////////////////////////////////
  760. // CTanksDoc commands
  761.